package com.corner.presenter.imp;


import android.support.annotation.Nullable;

import com.avos.avoscloud.im.v2.AVIMConversation;
import com.corner.R;
import com.corner.app.App;
import com.corner.model.cornerservice.domain.Conversation;
import com.corner.model.cornerservice.domain.ReportUser;
import com.corner.model.cornerservice.helper.ConversationHelper;
import com.corner.model.cornerservice.service.Service;
import com.corner.model.cornerservice.service.exception.BaseException;

import com.corner.model.db.Session;
import com.corner.model.db.SessionDao;
import com.corner.model.db.User;
import com.corner.model.db.UserDao;
import com.corner.model.leancloud.helper.HistoryMessageHelper;
import com.corner.model.leancloud.helper.MessageHelperV2;
import com.corner.presenter.IChatPresenter;
import com.corner.presenter.base.BasePresenter;
import com.corner.ui.view.IChatView;
import com.corner.utils.CollectionUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Observer;

import de.greenrobot.dao.query.QueryBuilder;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

import static com.corner.model.cornerservice.domain.User.*;


/**
 * Created by Administrator on 2015/7/13，19.11.
 * 描述：
 */
public class ChatPresenter extends BasePresenter<IChatView> implements IChatPresenter, Observer {

    public static final String FRIEND_AVATER_URL = "friendAvaterUrl";
    public static final String SELF_AVATER_URL = "selfAvaterUrl";
    public static final int PAGE_MESSAGE_SIZE = 10;
    private static final String FRIEND_NICK_NAME = "FRIEND_NICK_NAME";
    private boolean hasMore = true;
    private List<Session> sessions;
    private Date firstItemTime;
    private boolean isLoading;
    private String userIdInString;
    private SessionDao sessionDao;
    private UserDao userDao;

    public ChatPresenter() {
        if (App.application.daoSession==null) {
            App.application.initSession();
        }
        sessionDao = App.application.daoSession.getSessionDao();
        userDao = App.application.daoSession.getUserDao();
        sessionDao.addObserver(this);
    }

    @Override
    public void requestSessions(final String userIdToChatWith) {
        ChatPresenter.this.userIdInString = userIdToChatWith;
        Observable.create(new Observable.OnSubscribe<HashMap<String, Object>>() {
            @Override
            public void call(Subscriber<? super HashMap<String, Object>> subscriber) {
                final long userIdInLong = Long.parseLong(userIdToChatWith);
                HashMap<String, Object> map = new HashMap<String, Object>();
                User friend = userDao.load(userIdInLong);
                if (friend != null) {
                    String friendAvaterUrl = getUserAvater(friend);
                    map.put(FRIEND_AVATER_URL, friendAvaterUrl);
                    map.put(FRIEND_NICK_NAME,friend.getUsername());
                }
                User me = App.application.daoSession.getUserDao().
                        load(getCurrentUser().getObjectId());
                if (friend != null) {
                    String selfAvaterUrl = getUserAvater(me);
                    map.put(SELF_AVATER_URL, selfAvaterUrl);
                }
                QueryBuilder<Session> sessionQueryBuilder = sessionDao.queryBuilder();
                sessionQueryBuilder.where(SessionDao.Properties.SessionName.eq(userIdInString))
                        .orderDesc(SessionDao.Properties.Timestamp).limit(PAGE_MESSAGE_SIZE);
                sessions = sessionQueryBuilder.list();
                if (sessions != null) {
                    if (sessions.size() < PAGE_MESSAGE_SIZE) {
                        hasMore = false;
                    }
                    Collections.reverse(sessions);
                    setSessionsReaded(sessions);
                    setFirstTime();
                }
                subscriber.onNext(map);
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<HashMap<String, Object>>() {
                    @Override
                    public void call(HashMap<String, Object> map) {
                        if (view != null) {
                            view.showSessions(sessions, (String) map.get(SELF_AVATER_URL),
                                    (String) map.get(FRIEND_AVATER_URL),(String)map.get(FRIEND_NICK_NAME));
                            if (CollectionUtil.isCollectionEmpty(sessions)) {
                                getMoreFromServer();
                            }
                            view.comeToBottom();
                        }
                    }
                });
    }

    @Nullable
    private String getUserAvater(User user) {
        String avatarUrl = null;
        if (user.getAvatar()!=null) {
            avatarUrl = user.getAvatar().getFileUrl();
        }
        return avatarUrl;
    }

    @Override
    public void loadMoreSessions() {
        if (!hasMore || CollectionUtil.isCollectionEmpty(sessions)) {
            getMoreFromServer();
            return;
        }
        if (isLoading) {
            view.loadComplete();
            return;
        }

        Observable.create(new Observable.OnSubscribe<List<Session>>() {
            @Override
            public void call(Subscriber<? super List<Session>> subscriber) {
                isLoading = true;
                QueryBuilder<Session> sessionQueryBuilder = sessionDao.queryBuilder();
                sessionQueryBuilder.where(SessionDao.Properties.SessionName.eq(userIdInString),
                        SessionDao.Properties.Timestamp.lt(firstItemTime))
                        .orderDesc(SessionDao.Properties.Timestamp).limit(PAGE_MESSAGE_SIZE);
                List<Session> presessions = sessionQueryBuilder.list();
                if (CollectionUtil.isCollectionEmpty(presessions)) {
                    hasMore = false;
                } else {
                    if (presessions.size() < 10) {
                        hasMore = false;
                    }
                    Collections.reverse(presessions);
                }
                if (presessions != null) {
                    presessions.addAll(sessions);
                    sessions = presessions;
                    setSessionsReaded(sessions);
                    setFirstTime();
                    subscriber.onNext(sessions);
                }
                subscriber.onCompleted();
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<List<Session>>() {
            @Override
            public void call(List<Session> sessions) {
                if (view != null) view.showLoadMoreSessions(sessions);
                isLoading = false;
            }
        }, new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                if (view != null) view.loadComplete();
            }
        }, new Action0() {
            @Override
            public void call() {
                if (view != null) view.loadComplete();
            }
        });
    }

    /**
     * 从服务器获取更多的消息
     */
    private void getMoreFromServer() {
        MessageHelperV2.getHistoryAvimConversation(userIdInString, new MessageHelperV2.OnGetConversation() {
            @Override
            public void onGet(AVIMConversation conversation) {
                if (conversation == null&&view!=null) {
                    view.loadComplete();
                    return;
                }
                HistoryMessageHelper.GetPreMessageCallabck getPreMessageCallabck = new HistoryMessageHelper.GetPreMessageCallabck() {
                    @Override
                    public void onGetPreMessage(boolean isSucess) {
                        if (isSucess) {
                            hasMore = true;
                            loadMoreSessions();
                        } else if (view!=null){
                            view.loadComplete();
                        }
                    }
                };
                if (sessions == null || sessions != null && sessions.size() == 0) {
                    HistoryMessageHelper.getPreMessage(conversation, null, 0, getPreMessageCallabck);
                } else {
                    HistoryMessageHelper.getPreMessage(conversation, sessions.get(0).getMessageId(),
                            sessions.get(0).getTimestamp().getTime(), getPreMessageCallabck);
                }
            }
        });
    }

    @Override
    public void addToBlackList(final String userId) {
        view.showLoading(true);
        MessageHelperV2.addToBlackList(userId, new MessageHelperV2.AddToBlackCallBack() {
            @Override
            public void onGetResult(Boolean isSucess) {
                if (isSucess) {
                    if (view != null) {
                        view.addBlackListSucess();
                        view.showLoading(false);
                    }
                } else {
                    if (view != null) {
                        view.showError(App.application.getString(R.string.add_to_blacklist_failed));
                        view.showLoading(false);
                    }
                }
            }
        });
        ConversationHelper.getConversation(getCurrentUser().getObjectId(), Long.valueOf(userId)).map(new Func1<Conversation, Map<String, Object>>() {
            @Override
            public Map<String, Object> call(Conversation conversation) {
                if (conversation.getMainUser().getObjectId().
                        equals(getCurrentUser().getObjectId())) {
                    conversation.setMainIsInBlackList(true);
                } else {
                    conversation.setCustomIsInBlackList(true);
                }
                Map<String, Object> update = null;
                try {
                    update = Service.getInstance().conversationService.update(conversation.getObjectId(), conversation);
                } catch (BaseException e) {
                    e.printStackTrace();
                }
                return update;
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                .subscribe();
    }

    @Override
    public void report(final String userId) {
        view.showLoading(true);
        Observable.create(new Observable.OnSubscribe<Object>() {
            @Override
            public void call(Subscriber<? super Object> subscriber) {
                try {
                    ReportUser report = new ReportUser();
                    com.corner.model.cornerservice.domain.User user = new com.corner.model.cornerservice.domain.User();
                    user.setObjectId(Long.parseLong(userId));
                    report.setUser(user);
                    report.setCreateUser(getCurrentUser());
                    Service.getInstance().reportUserService.save(report);
                    subscriber.onNext(null);
                } catch (BaseException e) {
                    e.printStackTrace();
                    subscriber.onError(new Throwable(App.application.getString(R.string.report_user_failed)));
                }
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<Object>() {
            @Override
            public void call(Object o) {
                if (view != null) {
                    view.showReportSucess();
                    view.showLoading(false);
                }
            }
        }, new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                if (view != null) {
                    view.showReportError(throwable.getMessage());
                    view.showLoading(false);
                }
            }
        });
    }

    /**
     * 将sessions设置为读状态
     * @param sessions
     */
    public void setSessionsReaded(List<Session> sessions) {
        if (sessions != null && sessions.size() > 0) {
            sessionDao.updateToSentReaded(sessions.get(0).getSessionName());
        }
    }


    /**
     * 设置第一条记录的时间
     */
    private void setFirstTime() {
        if (sessions.size() > 0) {
            firstItemTime = sessions.get(0).getTimestamp();
        }
    }

    @Override
    public void update(java.util.Observable observable, Object data) {
        final Map<String, Object> change = (Map<String, Object>) data;
        final SessionDao.SessionOperate item =
                (SessionDao.SessionOperate) change.get(SessionDao.SESSION_OPERATE);
        if (item == SessionDao.SessionOperate.READ) {
            return;
        }else if (item== SessionDao.SessionOperate.INSERT_BATCH) {
            if (sessions==null||sessions!=null&&sessions.size()==0) {
                requestSessions(userIdInString);
            }
            return;
        }
        Observable.create(new Observable.OnSubscribe<List<Session>>() {
            @Override
            public void call(Subscriber<? super List<Session>> subscriber) {
                List<Session> newSessions = new ArrayList<Session>(sessions);
                switch (item) {
                    case INSERT:
                        Session session = (Session) change.get(SessionDao.SESSION);
                        if (userIdInString.equals(session.getFromUserId())
                                || userIdInString.equals(session.getToUserId()))
                            newSessions.add(session);
                        break;
                    case UPDATE:
                        session = (Session) change.get(SessionDao.SESSION);
                        updateSession(newSessions, session);
                        break;
                    case DELETE:
                        String sessionId = (String) change.get(SessionDao.SESSION_ID);
                        deleteSession(newSessions, sessionId);
                        break;
                }
                if (sessions != null && newSessions.size() > sessions.size()) {
                    setSessionsReaded(newSessions);
                }
                subscriber.onNext(newSessions);
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<List<Session>>() {
            @Override
            public void call(List<Session> sessions) {
                if (view == null)
                    return;
                view.showUpdateSessions(sessions);
                if (ChatPresenter.this.sessions.size() < sessions.size()) {
                    view.comeToBottom();
                }
                ChatPresenter.this.sessions = sessions;
                setFirstTime();
            }
        });
    }

    /**
     * 修改sessions中对应的session
     *
     * @param newSessions
     * @param session
     */
    private void updateSession(List<Session> newSessions, Session session) {
        for (int i = 0; i < newSessions.size(); i++) {
            Session session1 = newSessions.get(i);
            if (session1.getSessionId().equals(session.getSessionId())) {
                newSessions.remove(session1);
                newSessions.add(i, session);
            }
        }
    }

    /**
     * 产出sessions中对应id的session
     *
     * @param newSessions
     * @param id
     */
    private void deleteSession(List<Session> newSessions, String id) {
        Iterator<Session> iterator = newSessions.iterator();
        while (iterator.hasNext()) {
            Session session = iterator.next();
            if (session.getSessionId().equals(id)) {
                iterator.remove();
                break;
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        sessionDao.deleteObserver(this);
    }
}
